﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using CarolLib.WinService;
using DCS.Business.Interface;
using DCS.Business.Manager;
using DCS.Business.Model;
using DCS.DataProvider;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Threading;
using CarolLib;

namespace DCS.BusinessObject
{
    public class Parser : IMessageParser
    {
        static log4net.ILog Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        private static WinServiceSetting Settings = WinServiceConfiguration.GetConfig().Settings;
        static PRLMessageManager PRLmanager;
        static DCSFileManager DCSmanager;
        
        static readonly System.IFormatProvider culture = new System.Globalization.CultureInfo("en-US", true);
        static readonly Regex rgPDate = new Regex("[0-9]{2}[A-Z]{3}[0-9]{2}");
        static readonly Regex rgCarBin = new Regex("-[A-Z]{3}[0-9]{3}[A-Z]");
        static readonly char[] dot = { '.' };
        static readonly char[] slash = { '/' };
        static readonly char[] blank = { ' ' };

        static Dictionary<string, SSRCode> dicSPML;
        static Dictionary<string, SSRCode> dicSSR;

        Thread doCleanJob;

        #region IMessageParser Members

        public void Init()
        {
            IUnityContainer myContainer = new UnityContainer();
            UnityConfigurationSection section
              = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Containers["Data"].Configure(myContainer);

            IDataProvider dp = myContainer.Resolve<IDataProvider>();

            PRLmanager = new PRLMessageManager(dp);
            DCSmanager = new DCSFileManager(dp);

            lock (dot)
            {
                dicSPML = PRLmanager.GetSPMLs();
                dicSSR = PRLmanager.GetSSRs();
            }

            doCleanJob = new Thread(
                () => {
                    while (true)
                    {
                        Thread.Sleep(Settings.MainTaskInterval * 10);
                        CleanJob();
                    }
                }
            );
            doCleanJob.Start();
        }

        public void DetectAndParse(int batchSize, string messageType)
        {
            List<DCSFileGroup> groups = new List<DCSFileGroup>();

            try
            {
                groups = DCSmanager.GetFilesGroupToParse(batchSize, messageType);
            }
            catch (Exception e)
            {
                Logger.Error("error in DCSmanager.GetFilesGroupToParse", e);
            }

            if (groups.Sum(d => d.Count()) == 0)
            {
                Logger.Debug("There is no new PRL files. ");
                System.Threading.Thread.Sleep(10000);
                return;
            }

            List<PRLMessage> results = new List<PRLMessage>();

            Logger.DebugFormat("Begain to parse {0} groups, {1} PRL files", groups.Count, groups.Sum(g => g.Count));

            foreach (var group in groups)
            {
                try
                {
                    //排错代码，检查最后一个文件是否以ENDPRL结尾，若不是，则记录
                    //var file = group.Order().Last();
                    //string lastline = string.Empty;
                    //string last2rdline = string.Empty;
                            
                    //using (FileStream fs = new FileStream(file.LocalPath + "\\" + file.LocalFileName, FileMode.Open, FileAccess.Read))
                    //{
                    //    using (StreamReader reader = new StreamReader(fs, Encoding.UTF8))
                    //    {
                    //        while (!reader.EndOfStream)
                    //        {
                    //            last2rdline = lastline;
                    //            lastline = reader.ReadLine();
                    //        }
                    //    }
                    //}

                    //if (lastline.Trim() != "=" || last2rdline.Trim() != "ENDPRL")
                    //{
                    //    //异常
                    //    Logger.Fatal("==================发现异常报文==================");
                    //    Logger.Fatal(" ");
                    //    Logger.Fatal("===============================================");

                    //    continue;//跳过本组报文的解析
                    //}
                    //end排错代码，检查最后一个文件是否以ENDPRL结尾，若不是，则记录

                    results.AddRange(Parse(group));
                    group.ForEach(d => d.Status = FileStatus.FinishParse);
                }
                catch (Exception e)
                {
                    Logger.Error("Error In Parse() - ", e);
                    group.ForEach(d => d.Status = FileStatus.ParseError);
                }
            }


            try
            {
                PRLmanager.SaveEntities(results);
                Logger.DebugFormat("Parse {0} PRLMessages successful", results.Count);
                groups.ForEach(g => DCSmanager.UpdateDCSFilesStatus(g));
            }
            catch (Exception e)
            {
                Logger.Error(e);
            }
        }

        private List<PRLMessage> Parse(DCSFileGroup group)
        {
            List<PRLMessage> list = new List<PRLMessage>();
            PRLMessage model = null;
            StringBuilder sbContent = null;


            PRLMessage temp = new PRLMessage();
            string text = group.GroupName;
            temp.Carrier = text.Substring(0, 2);
            temp.FlightNo = text.Substring(2, text.IndexOf('_') - 2);
            temp.PDate = DateTime.ParseExact(rgPDate.Match(text).Value, "ddMMMyy", culture);
            temp.DeptAirport = text.Substring(text.Length - 7, 3);

            bool needContinue = false;

            foreach (var file in group.Order())
            {
                using (FileStream fs = new FileStream(file.LocalPath + "\\" + file.LocalFileName, FileMode.Open, FileAccess.Read))
                {
                    using (StreamReader reader = new StreamReader(fs, Encoding.UTF8))
                    {
                        text = string.Empty;
                        bool needRead = true;

                        while (!reader.EndOfStream)
                        {
                            #region Conditional ReadLine.

                            if (needRead)
                            {
                                text = reader.ReadLine();
                            }
                            else
                            {
                                needRead = true;
                            }

                            #endregion

							#region Continue

							try
							{
								if (needContinue)
								{
									if (text.StartsWith("."))
									{
										needContinue = false;

										sbContent.Append(text);

										text = reader.ReadLine();
										while (text.StartsWith("."))
										{
											sbContent.Append(text);
											text = reader.ReadLine();
										}
										if (text.StartsWith("1") || (text.StartsWith("-")) || (text.StartsWith("ENDPRL")))
										{
											// skip next readline.
											needRead = false;
											// save this one.
											string content = sbContent.ToString();
											sbContent = null;
											model = temp.Clone() as PRLMessage;
											model.RefFileId = file.FileId;
											FileMessageBody(model, content);

											list.Add(model);
										}
									}

                                    else if (text.StartsWith("1") || text.StartsWith("-") )
									{
										needContinue = false;

										// skip next readline.
										needRead = false;
										// save this one.
										if (sbContent != null)
										{
											string content = sbContent.ToString();
											sbContent = null;
											model = temp.Clone() as PRLMessage;
											model.RefFileId = file.FileId;
											FileMessageBody(model, content);

											list.Add(model);
										}
									}

                                    else if (text.StartsWith("ENDPRL"))
                                    {
                                        needContinue = false;

                                        // save last one.
                                        if (sbContent != null)
                                        {
                                            string content = sbContent.ToString();
                                            sbContent = null;
                                            model = temp.Clone() as PRLMessage;
                                            model.RefFileId = file.FileId;
                                            FileMessageBody(model, content);

                                            list.Add(model);
                                        }
                                    }
								}

							}
							catch (Exception ex)
							{
								Logger.Warn("Continue Error", ex);
							}

							#endregion

                            #region -XIY007F

                            if (rgCarBin.IsMatch(text))
                            {
                                temp.CabinNo = text.Substring(1);
                            }

                            #endregion

                            #region 1CHUANG/MINGCHUMS .L/THM35 .R/SEAT 5B .R/BN 027 .R/GATE 04

                            if (text.StartsWith("1"))
                            {
                                sbContent = new StringBuilder(text);
                                text = reader.ReadLine();
                                while (text.StartsWith("."))
                                {
                                    sbContent.Append(text);
                                    text = reader.ReadLine();
                                }
                                if (text.StartsWith("1") || (text.StartsWith("-")) || (text.StartsWith("ENDPRL")))
                                {
                                    // skip next readline.
                                    needRead = false;
                                    // save this one.
                                    string content = sbContent.ToString();
                                    sbContent = null;
                                    model = temp.Clone() as PRLMessage;
                                    model.RefFileId = file.FileId;

                                    try
                                    {
                                        FileMessageBody(model, content);
                                    }
                                    catch (Exception ex)
                                    {
                                        Logger.WarnFormat("Error FileMessageBody - " + file.RemoteFileName, ex);
                                    }

                                    list.Add(model);
                                }
                                else if (text.StartsWith("ENDPART"))
                                {
                                    // continue in next file.
                                    needContinue = true;
                                }
                            }

                            #endregion
                        }
                    }
                }
            }

            Logger.DebugFormat("Parse {0} OK.", group.GroupName);

            return list;
        }

        private void FileMessageBody(PRLMessage message, string content)
        {
            var pieces = content.Split(dot);

            message.ArrAirport = message.CabinNo.Substring(0, 3);

            foreach (string piece in pieces)
            {
                if (piece.StartsWith("1"))
                {
                    message.PName = piece.Substring(1).Trim();
                }
                else if (piece.StartsWith("L/"))
                {
                    message.PNR = piece.Substring(2).Trim();
                }
                else if (piece.StartsWith("R/SEAT"))
                {
                    message.Seat = piece.Substring(6).Trim();
                }
                else if (piece.StartsWith("R/BN"))
                {
                    message.BN = piece.Substring(4).Trim();
                }
                else if (piece.StartsWith("R/GATE"))
                {
                    message.GATE = piece.Substring(6).Trim();
                }
                else if (piece.StartsWith("W/K"))
                {
                    message.WK = piece.Substring(3).Trim();
                }
                else if (piece.StartsWith("N/"))
                {
                    message.Package += " " + piece.Substring(2).Trim();
                }
                else if (piece.StartsWith("M/"))
                {
                    message.ShareCode = piece.Substring(2).Trim();
                }
                else if (piece.StartsWith("O/"))
                {
                    message.OutBound = piece.Substring(2).Trim();
                }
                else if (piece.StartsWith("R/FQTV"))
                {
                    message.FQTV = piece.Substring(6).Trim();
                }
                else if (piece.StartsWith("R/FQTR"))
                {
                    message.FQTR = piece.Substring(6).Trim();
                }
                else if (piece.StartsWith("R/FQTS"))
                {
                    message.FQTS = piece.Substring(6).Trim();
                }
                else if (piece.StartsWith("R/FQTU"))
                {
                    message.FQTU = piece.Substring(6).Trim();
                }
                else if (piece.StartsWith("R/HC"))
                {
                    message.HC = piece.Substring(4).Trim();
                }
                else if (piece.StartsWith("R/TKNE"))
                {
                    if (message.TKNE==string.Empty)
                    {
                        message.TKNE = piece.Substring(6).Trim();
                    }
                    else
                    {
                        message.TKNE += " " + piece.Substring(6).Trim();
                    }
                }
                else if (piece.StartsWith("R/FOID"))
                {
                    message.FOID = piece.Substring(6).Trim();
                }
                else if (piece.StartsWith("R/PSPT"))
                {
                    message.PSPT = piece.Substring(6).Trim();
                }
                else if (piece.StartsWith("R/CNIN"))
                {
                    message.CNIN = GB2312Helper.GetGB2312ByOct(piece.Substring(6).Trim());
                }
                else if (piece.StartsWith("R/CKIN"))
                {
                    message.CKIN = piece.Substring(6).Trim();
                }
                else if (piece.StartsWith("R/PSM"))
                {
                    message.PSM = piece.Substring(5).Trim();
                }
                else if (piece.StartsWith("R/VIP"))
                {
                    message.IsVip = true;
                }
                else if (piece.StartsWith("RN/"))
                {
                    message.PSM += piece.Substring(3).Trim();
                }
                else if (piece.StartsWith("R/SPML"))
                {
                    string p = piece.Replace("NO BEEF", "HNML").Replace("/"," ");
                    string[] mls = p.Substring(6).Trim().Split(blank);
                    foreach (string ml in mls)
                    {
                        if (dicSPML.ContainsKey(ml))
                        {
                            message.SPML = (SPMLType)dicSPML[ml].Value;
                        }
                        else if (ml.EndsWith("ML"))
                        {
                            Logger.WarnFormat("There is a New SPML: {0}", ml);
                        }
                    }
                }
                else if (piece.StartsWith("R/"))
                {
                    int end = piece.IndexOf(' ') + 1;
                    if (end < 2)
                    {
                        end = piece.Length + 1;
                    }
                    string code = piece.Substring(2, end - 3).Trim();
                    if (dicSSR.ContainsKey(code))
                    {
                        message.SSR |= (SSRType)dicSSR[code].Value;
                    }
                    else
                    {
                        Logger.WarnFormat("There is a New SSR: {0}", code);
                    }
                }
            }
        }

        private void CleanJob()
        {
            List<DCSFile> badEnds=new List<DCSFile>();

            try
            {
                badEnds = DCSmanager.GetDCSFilesByMessageType("PRL", FileStatus.FinishDownload, 100)
                .Where(f => f.DownloadTime < (DateTime.Now.AddMilliseconds(-500 * Settings.MainTaskInterval))).ToList();
            }
            catch(Exception e)
            {
                Logger.Error(e);
                return;
            }

            foreach (var item in badEnds)
            {
                try
                {
                    using (FileStream fs = new FileStream(item.LocalPath + "\\" + item.LocalFileName, FileMode.Open))
                    {
                        using (StreamReader reader = new StreamReader(fs, Encoding.UTF8))
                        {
                            string text = reader.ReadToEnd();
                            if ((text.IndexOf("TKNE") == -1) || (text.IndexOf(".L/") == -1))
                            {
                                //string preName = item.LocalFileName.Replace("PART" + item.PartNo.ToString(), "PART" + (item.PartNo - 1).ToString());
                                item.Status = FileStatus.FinishParse;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.Warn("Error in CleanJob() - " + item.RemoteFileName, ex);

                    // item.Status = FileStatus.FinishClean;
                        item.Status = FileStatus.FinishParse;
                    
                }

                try
                {
                    DCSmanager.UpdateDCSFilesStatus(badEnds.Where(f => (f.Status == FileStatus.FinishParse)).ToList());
                }
                catch (Exception e)
                {
                    Logger.Error(e);
                }
            }
        }

        #endregion
    }
}
